﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Web;

namespace KIS公有云测试.Tools
{
    public enum LogLevel
    {
        Debug,
        Info,
        Error
    }
    /// <summary>
    /// 文本日志
    /// </summary>
    public class ConcurrentLogger
    {
        private static readonly ConcurrentQueue<LogEntry> LogQueue = new ConcurrentQueue<LogEntry>();
        private static readonly Thread LogWriterThread;
        private static bool _isRunning;
        private static readonly object _lock = new object();
        private static readonly StringBuilder _buffer = new StringBuilder();
        private static readonly int _batchSize = 100;
        private static readonly int _flushInterval = 5000; // 5 seconds
        private static readonly string _logDirectory;

        static ConcurrentLogger()
        {
            _isRunning = true;
            LogWriterThread = new Thread(WriteLogs)
            {
                IsBackground = true, // 设置为后台线程，防止阻止应用程序退出
                Name = "LogWriterThread"
            };
            _logDirectory = HttpRuntime.AppDomainAppPath;//Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
            LogWriterThread.Start();
        }

        //public static void Log(LogLevel level, string message, string eventName = "Event")
        //{
        //    LogQueue.Enqueue(new LogEntry(level, message, eventName));
        //}
        public static void Log(LogLevel level, string message, string eventName = "Event", string methodName = null)
        {
            LogQueue.Enqueue(new LogEntry(level, message, eventName, methodName));
        }
        private static void WriteLogs()
        {
            while (_isRunning)
            {
                try
                {
                    if (LogQueue.Count >= _batchSize)
                    {
                        FlushLogs();
                    }
                    else
                    {
                        Thread.Sleep(_flushInterval);
                    }
                }
                catch (Exception ex)
                {
                    // Handle exceptions, e.g., log to Event Viewer or another logging system
                    Console.WriteLine($"Failed to write logs: {ex.Message}");
                }
            }
        }

        private static void FlushLogs()
        {
            var entries = new LogEntry[_batchSize];
            int count = 0;

            while (count < _batchSize && LogQueue.TryDequeue(out LogEntry entry))
            {
                entries[count++] = entry;
            }

            if (count > 0)
            {
                lock (_lock)
                {
                    for (int i = 0; i < count; i++)
                    {
                        string logMessage = $"{entries[i].Level}, {entries[i].Timestamp:yyyy-MM-dd HH:mm:ss}, {entries[i].EventName}, {entries[i].MethodName}, {entries[i].Message}";
                        _buffer.AppendLine(logMessage);
                    }

                    if (_buffer.Length > 0)
                    {
                        string logFileName = $"application_{DateTime.Now:yyyyMMdd}.log";
                        string logFilePath = Path.Combine(_logDirectory, logFileName);
                        try
                        {
                            File.AppendAllText(logFilePath, _buffer.ToString());
                            _buffer.Clear();
                        }
                        catch (Exception ex)
                        {
                            // Handle exceptions, e.g., log to Event Viewer or another logging system
                            Console.WriteLine($"Failed to write log to file: {ex.Message}");
                            // Optionally, store failed logs in a separate queue for retry
                        }
                    }
                }
            }
        }

        public static void Stop()
        {
            _isRunning = false;
            LogWriterThread.Join();
            FlushLogs(); // Ensure all remaining logs are flushed
        }

        private class LogEntry
        {
            public LogLevel Level { get; }
            public DateTime Timestamp { get; }
            public string Message { get; }
            public string EventName { get; }
            public string MethodName { get; }

            public LogEntry(LogLevel level, string message, string eventName, string methodName)
            {
                Level = level;
                Timestamp = DateTime.Now;
                Message = message;
                EventName = eventName;
                MethodName = methodName;
            }
        }
        private string GetCurrentDllPath()
        {
            return Assembly.GetExecutingAssembly().Location;
        }
    }
}